# 25. 华为od面试2026

# 1. 类似牛客网的机试

有智能补全,选 JavaScript Node 后会给一个输入输出的例子。而且已经不是 readline 模式了,和 leetcode 差不多了,需要 return 返回。

  1. 统计特殊数字 (opens new window)
  2. 矩阵螺旋遍历 (opens new window)
  3. 基站最小覆盖半径[200分] (opens new window)

最后260分。1、2题共200分,3题不会,用例过了30% 60分。

# 2. 性格测试

参考之前的 od 面试 105 题(性格测试),不限制时间。

# 3. hr资格面

# 3.1 面试问题清单

  1. 自我介绍
  2. 各个公司离职原因
  3. 工资构成
  4. 是否有其他 offer
  5. 英语 4 级为啥没过,只考了一次
  6. 上家公司有多少人,你带了几个人,负责什么?
  7. 是否了解华为部门岗位,数字与能源
  8. 你说领导对你很好,好在哪?

# 3.2 自我介绍(模板)

面试官您好,我是 XXX,XX 大学 XX 专业,前端开发 X 年。 工作经历一共 5 段:前两段分别在公路工程行业信息化和地图可视化方向,先把前端基础打扎实了;中间在腾讯子公司做 toB 业务,主要是工单管理平台和坐席 AI 智能助手 SDK;最近一段在华胜天成继续做前端开发。 技术上主要以 Vue 2 / Vue 3 + TypeScript 为主,熟悉 Webpack / Vite 工程化、性能优化、WebSocket 实时通信,也做过地图可视化相关业务(实时位置、历史轨迹、报警联动)。 我最近讲得比较多的项目是用 Vue 3 写的一个坐席 AI 智能助手前端 SDK,第三方呼叫中心系统引入一个 script、调一次 init 就能接进去,通话中通过 WebSocket 接收实时 ASR 字幕、AI 通话小结、实时质检等多路消息。 我个人的特点是比较能扛压、上手快,这次希望找一个业务稳定、能长期做下去的平台,所以特别希望能加入华为。

# 3.3 离职原因

第一份:公路工程公司(毕业后的第一份)

毕业后我花了一段时间想清楚职业方向。当时先进入公路工程行业做信息化相关的工作,在这个过程中发现自己对前端技术开发更有热情,也更想往互联网技术方向发展。所以经过慎重考虑,我决定转向前端方向,为此做了系统学习和项目准备。

注意:不要说是"没想好随便去的",要包装成"探索期后明确方向"。

第二份:武汉地大公司

在这家公司我主要负责地图相关的前端开发,领导和工作氛围都很好。但技术栈相对传统,我希望能接触到更主流、更新的前端技术体系,提升自己的技术竞争力,所以选择了离开。这段经历让我打下了扎实的前端基础,也让我更清楚自己要往哪个方向走。

第三份:上海上讯

上讯离开是因为我当时非常想去更大的平台发展,接触更高复杂度的业务和更成熟的技术体系,所以选择了腾讯的机会。

第四份:腾讯(子公司)

腾讯这段经历让我学到了很多,尤其是大厂的技术规范和协作流程。后来因为公司内部业务调整,降本增效,西安、长沙、上海的组都被砍掉了。

第五份:华胜天成

华胜天成也是因为公司内部业务调整,业务不稳定,西安和上海整个团队都被裁撤了。这两段经历让我更加希望找一个业务稳定、平台大、能长期发展的公司,所以华为是我的首选。

所有离职原因归为"个人发展"或"业务调整",所有回答指向"我想在华为长期稳定发展,能扛压、能加班、能快速上手"。

# 3.4 为什么来华为?

主要有三个原因:

  1. 华为是我一直很认可的平台,技术积累深、业务稳定、体系成熟,能让我长期深耕;
  2. 我有朋友在华为,了解到这边虽然节奏快、要求高,但成长也很快,我希望能在这种环境里提升自己;
  3. 我之前的经历里有几段是因为公司业务调整被动离开,所以我现在更看重平台的稳定性和长期发展空间,华为正好符合我的诉求。

# 3.5 华为能给你带来什么?你能给华为创造什么价值?

华为能给我带来的是:更大的技术平台、更规范的研发流程、更高复杂度的业务场景,以及持续学习和成长的机会。

我能给华为带来的是:

  • 扎实的前端开发能力,能快速上手业务;
  • 多段不同公司的经历,让我适应能力比较强,能快速融入团队;
  • 我做过多段不同业务,技术面比较广,能应对不同需求;
  • 我抗压能力强,愿意加班投入,能保证交付。

# 3.6 职业规划

  • 短期(1-2 年):快速熟悉华为的业务和技术栈,成为团队里能独立承担模块开发的人;
  • 中期(3-5 年):在前端领域深耕,往技术专家或技术骨干方向走,能带小团队或负责核心模块;
  • 长期:希望在华为长期发展,跟着平台一起成长。

注意:不要说"想转管理"或"想创业",华为OD更看重你能不能踏实干活。

# 3.7 如何看待加班?(压力面)

我理解华为的节奏,也做好了心理准备。我之前在腾讯和华胜天成的时候,也有过项目紧张期加班的情况,我是能接受的。我认为加班是为了保证项目交付,只要是有目标、有节奏的加班,我是愿意配合的。当然,我也会尽量提升效率,减少不必要的加班。

注意:不要问"加班多不多",不要表现出犹豫。

# 3.8 工资构成怎么答?

先把结构说清楚,再给期望值,不要只甩一个月薪数字。

我的构成是:基本工资 + 绩效工资 + 年终奖(X 个月)+ 补贴(餐补 / 交通 / 话补)+ 加班费或调休,公积金按 X% 缴,社保公积金基数按实/按最低。目前税前月薪 X,年包大概 X 万(含年终和补贴)。

期望上:希望比现在有合理涨幅(市场常见 20%~30%,具体看定级),也希望能了解华为这边的薪资结构和绩效规则。

# 3.9 手里有没其他 offer?

目前没有,刚离职不久,想先全力准备华为的面试。

# 3.10 英语 4 级为啥没过,只考了一次?

在校时精力主要放在专业课和项目上,英语只按应试准备了一次,确实是重视不够,这是我自己的问题,不找客观理由。

但实际工作中英文不是障碍:技术文档、报错信息、GitHub issue、API 文档基本都是英文的,我平时搜索和看源码都在用英文;口语上日常读写没问题。如果岗位有硬性要求,我愿意再考,也会继续补英语。

(要点:承认 + 不贬低自己 + 用工作事实补位 + 给出口。)

# 3.11 是否了解华为部门岗位(数字与能源)?

提前做过功课,可以这样答:

数字能源是华为的重点业务方向之一,围绕清洁发电、能源数字化、交通电动化、站点与数据中心能源基础设施、综合智慧能源这些场景,前端侧主要是能源数字化平台、监控运维系统、数据可视化大屏这类系统——业务属性强、数据量大、对实时性和稳定性要求高。

我的匹配点:

  • 做过实时数据链路(WebSocket 长连接 + 多路消息分发 + 断线重连),能应对实时监控类场景;
  • 做过地图可视化(实时位置、历史轨迹、报警),可视化大屏类需求上手快;
  • 做过 SDK 化交付(嵌入第三方系统、样式隔离、生命周期管理),对接集成类场景有经验。

(要点:先说部门业务方向 → 再说岗位可能的系统形态 → 最后落到自己的可迁移经验。)

# 3.12 你说领导对你很好,好在哪?

从四个角度答,落到"所以我成长快、也愿意跟这样的领导长期干":

  1. 信任与放权:重要需求敢交给我独立负责,方案让我自己定,只在关键节点对齐,这让我成长很快;
  2. 愿意给反馈:代码 review 会直接指出问题,需求优先级也会帮我梳理,做错了当场说清楚,不搞"背后评价";
  3. 替我争取:绩效、调级、好项目机会都会帮团队争取,团队拿结果时他会替大家说话;
  4. 氛围和担当:需求临时变更、线上出问题,他先挡住压力、再一起解决,不甩锅。

# 3.13 看你之前面过华为 od,最后为啥没来?

当时是先拿到华胜天成的 offer 了,而且业务方向也挺匹配的,所以就去了,入职后才过了华为的 offer,已经入职了想稳定做一段,不想刚去就离职。

# 4. 技术一面

# 4.1 自我介绍

毕业院校、专业、工作经历、项目经历、技术栈(话术见 3.2 自我介绍)。

# 4.2 项目过程中遇到的难题

答"辅助 SDK 的开发需求"(坐席 AI 智能助手前端 SDK),一个主难点 + 一个备选难点:

难点一:把一个 Vue 3 应用做成"可嵌入任意第三方系统的 SDK"

  • 生命周期管理:内部用 createApp(App) 动态挂载到宿主节点或自建容器,destroy() 时要 unmount() + 移除 DOM + 清空引用,否则宿主页面内存泄漏、事件残留;
  • 样式隔离:CSS 打进 JS 运行时注入,统一加作用域前缀,既不污染宿主也不被宿主干扰;
  • 对外 API 设计:只暴露 init / login / logout / destroy + 白名单事件订阅,内部用事件总线桥接,内外完全解耦;
  • 资源冲突:z-index 不写死,用全局递增调度,避免和宿主弹窗打架。

难点二:WebSocket 实时链路的可靠性

  • "连接假死":onopen 已触发、socket 显示连着,但后端其实断了,不推数据也不触发 close,字幕静默消失。解法是自建心跳 ping/pong(连续 5 次没回 pong 主动重连)+ reconnecting-websocket 自动重连;
  • 流式字幕时序:整句和半句混着来,要区分"替换当前半句"还是"落一条完整记录",断线期间按 message_id 去重。

细节见 16. 面试问题1 (opens new window)。

# 4.3 null 和 undefined 的区别

null 和 undefined 都表示"没有值",但在 JavaScript 中它们的含义、产生方式和典型用途有明显区别。

核心区别一句话:

  • undefined 通常是"系统自动给的"——变量声明了但没赋值、函数没返回值、访问不存在的属性等。
  • null 通常是"人为主动设置的"——表示"这里 intentionally 就是空"。

1. 含义与语义

  • undefined:表示"未定义/缺失",是引擎在缺少值时自动产生的。
  • null:表示"空值/无对象",一般由开发者显式赋值,用来清空或占位。

2. 类型

typeof undefined // "undefined"
typeof null      // "object"  ← 这是 JS 的历史遗留 bug
1
2

注意 typeof null === "object" 不代表 null 是对象,只是早期实现遗留问题。

3. 常见产生场景

场景 undefined null
变量声明未赋值 ✅ ❌
函数无返回值 / 无 return ✅ ❌
访问对象不存在的属性 ✅ ❌
函数调用未传参 ✅ ❌
原型链终点 Object.prototype.__proto__ ❌ ✅
正则 match 无匹配结果 ❌ ✅
JSON.parse('null') ❌ ✅

4. 转换与比较(常被追问)

Number(null)      // 0
Number(undefined) // NaN
null == undefined // true   (宽松相等规则里两者互等)
null === undefined// false
JSON.stringify({ a: null, b: undefined })  // '{"a":null}'  → undefined 的键会被丢弃
JSON.stringify([null, undefined])          // '[null,null]' → 数组里 undefined 变 null
1
2
3
4
5
6
  • 默认值只在 undefined 时生效:function f(a = 1) {},f(null) 拿到的是 null,不是 1;解构默认值 const { a = 1 } = { a: null } 同理。
  • 判断方式不同:判断 null 用 x === null;判断 undefined 用 typeof x === 'undefined',因为未声明的变量直接用 x === undefined 会报 ReferenceError。

5. 使用建议

  • 需要"显式置空"时用 null(比如释放对象引用、接口约定字段为空);
  • 不要给变量手动赋 undefined,交给引擎产生即可;
  • 判断"没值"时用 x == null 可以一次覆盖 null 和 undefined 两种情况。

# 4.4 vue2 升级到 vue3 的难题

升级过程见 10. vue2迁移到vue3 (opens new window)(完整答案见 5.8),实际遇到的难点集中在:

  1. 老代码体量大:几千个文件不可能一次重写,只能先跑 @vue/compat 兼容构建,把告警按类型分批清掉;
  2. 第三方库不支持 Vue 3:部分老组件库/图表封装没有 Vue 3 版本,只能替换或自己包一层适配;
  3. 行为差异踩坑:$children 移除、事件总线 $on/$off 移除(换 mitt)、filter 移除、v-model 语义变化、$listeners 合并进 $attrs、生命周期改名;
  4. 构建链路:vue-cli / webpack 配置里 loader、plugin 都要跟着升,顺手迁到 Vite 时环境变量、静态资源引用方式都要改;
  5. 回归成本高:升级后必须靠完整回归 + 自测兜底,所以分模块灰度上线,先非核心页再核心页。

# 4.5 你熟悉的设计模式有哪些

先给一句总述,再"一个模式 + 一个项目里的真实用法",比背定义分高。

设计模式 在前端 / 项目中的用法
单例模式 Pinia/Vuex store、全局弹窗、SDK 实例(init 时加守卫防止重复挂载出双实例)
发布订阅 / 观察者 Vue 响应式(Dep/Watcher)、事件总线(mitt)、WebSocket 一路 message 分发给字幕/质检/小结多个模块
策略模式 按 msg_type 分发的处理器映射表、表单校验规则,替代一长串 if-else
工厂模式 按消息类型/组件类型创建对应的处理器或组件实例
代理模式 Vue 3 Proxy 响应式、图片懒加载、防抖节流与接口层的统一封装
适配器模式 不同宿主系统、不同后端字段差异,用适配层统一成内部数据结构
装饰器 / 高阶函数 axios 拦截器、unplugin-auto-import 式的语法糖、埋点与日志包装
模块 / 闭包模式 SDK 内部状态用闭包私有化,避免污染宿主全局变量
状态模式 通话状态机(待接入 → 通话中 → 挂断)驱动 UI 显示

我讲得最多的两个:发布订阅(WebSocket 消息分发 + 事件总线解耦内外)和策略模式(消息类型处理器表,加一种消息只加一个处理器,不改主流程)。

# 4.6 算法题:班委选举

题目: 一次班委选举,导员收集了大家关于班长的投票结果,按照以逗号间隔的方式记录了一组姓名拼音,名字和名字之间逗号隔开,请协助导员统计下候选人的票数,按照票数高低的顺序输出名字空格票数,如果相同票数的情形下按照字母升序输出。

输入

xiaoming,xiaozhang,xiaoli,zhangsan,xiaoming
1

输出

xiaoming 2, xiaoli 1, xiaozhang 1, zhangsan 1
1
const input = 'xiaoming,xiaozhang,xiaoli,zhangsan,xiaoming';

function sortHeader(str) {
  // 1. 用 Map 统计票数,避免用对象时 __proto__、constructor 这类键名踩坑
  const count = new Map();
  for (const name of str.split(',')) {
    const key = name.trim();
    if (!key) continue;
    count.set(key, (count.get(key) || 0) + 1);
  }
  // 2. 票数降序;票数相同时按字母升序
  return [...count.entries()]
    .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
    .map(([name, num]) => `${name} ${num}`)
    .join(', ');
}

console.log(sortHeader(input)); // xiaoming 2, xiaoli 1, xiaozhang 1, zhangsan 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

原代码的两个问题(容易被面试官追问):

  1. 票数相同时写的是 a[0] - b[0],字符串相减得到 NaN,比较函数结果不确定,排序等于没生效;字符串排序要用 localeCompare 或 a[0] < b[0] ? -1 : 1。
  2. 返回的是二维数组,而题目要求输出 名字 空格票数 用逗号拼接的字符串,需要再 map + join 一次。

# 5. 技术二面

# 5.1 手撕代码:合并区间

题目: 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

示例 1

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
1
2
3

示例 2

输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
1
2
3

提示

  • 1 ≤ intervals.length ≤ 10^4
  • intervals[i].length == 2
  • 0 ≤ starti ≤ endi ≤ 10^4
const intervals = [[1, 3], [2, 6], [8, 10], [15, 18]];

function merge(intervals) {
  if (!intervals.length) return [];
  // 1. 拷贝一份再按起点升序排序,避免修改调用方传入的数组
  const arr = intervals.map((item) => item.slice()).sort((a, b) => a[0] - b[0]);
  const ans = [arr[0].slice()];
  for (let i = 1; i < arr.length; i++) {
    const last = ans[ans.length - 1];
    const [start, end] = arr[i];
    // 2. 当前区间起点大于上一段终点 → 不重叠,直接开新段;否则合并取较大终点
    if (start > last[1]) {
      ans.push([start, end]);
    } else {
      last[1] = Math.max(last[1], end);
    }
  }
  return ans;
}

console.log(merge(intervals)); // [[1,6],[8,10],[15,18]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

复杂度: 排序 O(n log n),遍历 O(n);空间 O(n)(排序 + 结果)。注意点: 判断重叠用 start > last[1](不是 >=),所以示例 2 的 [1,4]、[4,5] 会正确合并成 [1,5]。

原代码的三个问题(面试官一定会看):

  1. 循环里用的是 intervals.length,但排序后的数组是 arr,两个数组不一致(这里长度相同才没出错),应该用 arr.length;
  2. ans.push(arr[0])、ans.push(arr[i]) 都是直接塞引用,后续 ans[ans.length - 1][1] = ... 会改掉入参里的原区间,属于副作用 bug,要 slice() 或新建数组;
  3. 起始分支用 i === 0 特判,不如直接把第一段推进结果再从 i = 1 开始,少一次判断。

# 5.2 vue2 和 vue3 的差异,为什么用 Proxy

一句话:Vue 2 用 Object.defineProperty 递归劫持每个属性,Vue 3 改成用 Proxy 代理整个对象,解决了 Vue 2 响应式的能力缺陷和初始化性能问题。

Vue 2 的四个痛点(正是换 Proxy 的直接原因)

  1. 只能劫持已存在的属性:新增 / 删除属性不响应,必须用 Vue.set / Vue.delete;
  2. 数组只重写了 7 个方法(push/pop/shift/unshift/splice/sort/reverse),arr[0] = x、arr.length = 0 这种写法不触发更新;
  3. 初始化时递归遍历对象所有层级,数据再大也要一次性转成响应式,首屏开销大(哪怕这些数据压根没用到);
  4. 无法劫持 Map/Set/WeakMap/WeakSet 等集合类型。

Proxy 的优势

  1. 代理整个对象,可以拦截 get/set/deleteProperty/has/ownKeys,新增删除属性天然响应式,不再需要 $set;
  2. 支持数组索引和 length 直接赋值;
  3. 惰性代理:只有真正访问到某个属性时,才把返回的对象递归转成响应式,初始化更快、内存更省;
  4. 支持 Map/Set 等集合类型(内部用一套 collection handlers);
  5. 代价:IE 不支持且没法 polyfill;每次读写多一层 Proxy 拦截,Vue 3 用缓存(reactiveMap)、shallowRef/markRaw 等手段规避额外开销。

其他差异(顺带说,别只答响应式)

  • API:选项式 → 组合式(setup、ref/reactive、显式导入 computed/watch),逻辑复用从 mixin 变成组合式函数;
  • 生命周期:destroyed → unmounted,beforeDestroy → beforeUnmount;
  • 编译期性能优化:静态提升、patchFlag、Block Tree、最长递增子序列求最小移动次数,diff 更快;
  • 打包体积:支持 Tree-shaking,只打包用到的 API;
  • 新特性:Fragment(多根节点)、Teleport、Suspense、defineComponent;
  • 破坏性变更:filter 移除、$on/$off/$once 移除(事件总线改 mitt)、$children 移除、v-model 语义变化、.sync 移除、$listeners 合并进 $attrs;
  • 工程体验:Vite + TypeScript 支持更好,类型推导和编辑器提示明显更强。

参考:7. vue响应式原理 (opens new window)、17. 面试问题2 (opens new window)。

# 5.3 企点中的"多 set"是什么

背景:当时只有一套测试环境,多个需求并行开发时互相耦合——一个人改的代码会影响别人测试,需求排期互相卡。

目标:把一套测试环境变成多套(set1 ~ set10),不同主号(账号)走不同的 set 环境,需求之间彻底隔离。

做法(本质是"打包部署时多一层目录 + 运行时按账号路由"):

  1. 部署侧:项目用 Coding 流水线部署,给流水线加 env(环境)和 set(第几套)两个参数,往 COS 发资源时路径多拼一层,比如 set_2_8,资源就落到服务器上对应的 set 目录;
  2. 访问侧:用户登录后 cookie 里有主号,nginx 匹配静态资源路径时先看 cookie 里有没有 qidian_env_set,有就直接拼到路径上取对应 set 的资源;
  3. 兜底:cookie 里没有时,用 lua 脚本调接口拿到该主号的 env 和 set,拼接路径并写回 cookie,下次直接命中。

结果:多个需求可以并行在各自的 set 上开发测试,互不干扰。

收获与反思:顺带学会了 lua 在 nginx 里的应用;反思是"多 set"之后账号和 set 的对应关系、每个 set 上跑着哪些需求,必须做台账记录,否则后面找人、找环境会非常乱。

细节见 16. 面试问题1 (opens new window)。

# 5.4 企点中的项目性能优化是怎么做的

按"先量指标,再分层优化"的思路答,分四层说:

1. 指标先行(先说什么叫"快")

  • 加载类:FCP(首次内容绘制)、LCP(最大内容绘制)、TTI、首屏时间、资源体积、请求数;
  • 交互类:FPS、长任务(long task)、输入延迟;
  • 工具:Lighthouse / Performance 面板 / performance.getEntriesByType('navigation') 打点上报。

2. 网络与加载层

  • 路由懒加载 + 组件按需引入,控制首屏包体积;
  • CDN 加速、gzip/Brotli 压缩、HTTP/2 多路复用;
  • 关键资源 preload / preconnect,非关键脚本 defer/async;
  • 静态资源带 hash 走强缓存,HTML 走协商缓存。

3. 渲染层

  • 长列表用虚拟滚动 + 分页,避免一次渲染上千个工单节点;
  • 动画只用 transform / opacity,避免触发 reflow;批量读写 DOM,减少回流重绘;
  • 图片懒加载、大图压缩与 CDN 裁剪。

4. 框架与业务层

  • Vue:v-once / v-memo、keep-alive 缓存页面、shallowRef/shallowReactive 避免大对象深度响应式、computed 缓存派生数据;
  • 实时链路:用 WebSocket 推送替代轮询,减少无效请求;
  • SDK 场景:控制产物体积(按需打包、把宿主已有的依赖 externals 掉,不重复打包)、样式注入不影响宿主首屏。

(更全的方法清单见 23. 性能优化方法 (opens new window)。)

# 5.5 事件循环是什么

一句话:JS 是单线程的,事件循环(Event Loop)就是"调用栈 + 任务队列"的调度机制——同步代码在栈上跑,异步任务的回调按宏任务 / 微任务分队列排队,栈空了就按规则取出来执行。

执行顺序(背下来):

  1. 先执行同步代码(主线程调用栈);
  2. 同步代码执行完 → 清空微任务队列(Promise.then、queueMicrotask、MutationObserver),期间产生的新微任务也一并清空,直到队列为空;
  3. 从宏任务队列取一个任务执行(setTimeout、setInterval、I/O、UI 渲染、MessageChannel);
  4. 执行完这个宏任务 → 再清空一次微任务队列;
  5. 回到第 3 步,循环往复。

口诀:先同步,再微任务,后宏任务;每执行一个宏任务,必清空一次微任务。

经典例题

console.log('1');
setTimeout(() => console.log('2'));           // 宏任务
Promise.resolve().then(() => console.log('3')); // 微任务
console.log('4');
// 输出:1 4 3 2
1
2
3
4
5

加分点

  • Node.js 的事件循环还分 timers / pending callbacks / poll / check / close callbacks 等阶段,process.nextTick 优先级高于 Promise;
  • 浏览器里渲染(一帧)也是一个宏任务级别的时机,"微任务在渲染前执行"正是 nextTick 用微任务的原因(见 5.9);
  • 微任务如果一直互相递归,会饿死宏任务和渲染,导致页面卡死。

参考:11. 前端面试可能会问到? (opens new window)、17. 面试问题2 (opens new window)。

# 5.6 开发中如何用 AI

核心原则:AI 做执行、我做决策;AI 生成、我 review;最终质量和结果由我负责。落地成一条工作流:

  1. 规范前置:把团队开发规范、技术栈、组件库约定、命名规范沉淀成 Skills / instructions 给 AI,让 AI 一开始就"懂规矩",减少重复纠正;
  2. 需求 → 方案:自己先读透需求和边界,再让 AI 输出模块拆分、技术选型、数据结构、风险点,方案我拍板;
  3. 开发:先让 AI 出骨架 + 类型/接口定义,再按方案逐步实现,每一步确认后再往下;关键用例先让 AI 写测试;
  4. 还原与联调:Figma MCP 按设计稿生成代码 + mock 数据;接口文档通过 MCP 喂给 AI 按真实字段改代码,避免手抄出错;
  5. 自测与 BugFix:把报错栈、复现路径、期望行为给 AI 定位问题,但每个 patch 我都会先理解根因再合入;
  6. 底线:AI 生成 ≠ 可靠(安全、核心逻辑必须人肉把关);AI 不背锅;踩过的坑和有效提示词持续沉淀。

详细版见 22. ai相关问题 (opens new window)。

# 5.7 用 AI 的时候会整理 skill 吗

会,而且我是把 skill 当作"团队规范的可执行版本"在用:

  1. 沉淀什么:项目的技术栈与版本约定、目录与命名规范、组件库 / 工具函数的用法、接口封装约定、代码风格与提交规范、踩过的坑(比如"这个组件库的 X 属性不要用");
  2. 放在哪:写成 copilot-instructions.md、.instructions.md、SKILL.md、自定义 agent 或 prompt 模板,随仓库一起走,团队共享;
  3. 好处:AI 一次"懂规矩"后输出天然贴合团队规范,少来回纠正;新人也能直接复用,等于把口口相传的经验文档化;
  4. 怎么维护:把每次踩的坑、有效的提示词回写到 skill 里,让它越用越准,而不是一次写完不管。

一句话:代码是产物,skill 是把经验变成可复用的生产力。

# 5.8 vue2 如何迁移到 vue3

完整变更清单见 10. vue2迁移到vue3 (opens new window),流程可以这样讲:

1. 准备

  • 先升级 Node / 构建工具(vue-cli 或 webpack 相关 loader、plugin),保证工程能跑;
  • 装 @vue/compat 兼容构建,把 vue 别名指向它,配置 compilerOptions.compatConfig,先让老代码在 Vue 3 下跑起来,再看控制台告警。

2. 代码层面(按告警分批改)

  • 全局 API:new Vue() → createApp(),Vue.use → app.use,Vue.prototype.x → app.config.globalProperties.x,Vue.nextTick → 从 vue 里导入 nextTick;
  • 生命周期:beforeDestroy/destroyed → beforeUnmount/unmounted;
  • 事件与通信:$on/$off/$once 移除 → 换 mitt 事件总线;$listeners 合并进 $attrs;$children 移除 → 用 ref 或 provide/inject;
  • 模板语法:filter 移除 → 改成方法或 computed;v-model 语义变化(多个 v-model、去掉 .sync);v-if 与 v-for 优先级反转;插槽统一用 v-slot;
  • 响应式:Vue.set/delete 不再需要,可直接赋值;
  • 组件:函数式组件改写成普通函数 + props,emits 选项显式声明事件,异步组件改用 defineAsyncComponent;
  • 状态管理:Vuex 可平滑保留,想升级就换 Pinia,mapState 等方式也要跟着改。

3. 渐进式策略(重点,体现工程能力)

  • 不要一次重写:先修构建报错 → 再修运行时告警 → 按模块灰度迁移,非核心页先上;
  • 用 vue-codemod / gogocode 自动转换一部分机械性改造,人工只处理逻辑差异;
  • 每批改动都跑完整回归 + 自测,保证线上不出问题。

4. 收尾

  • 全部告警清零后去掉 @vue/compat,享受 Tree-shaking 和编译优化带来的体积 / 性能收益;
  • 可选迁到 Vite,开发启动和热更新都会明显变快。

# 5.9 vue 中为什么 nextTick 用的是微任务

要分两层答:nextTick 解决什么问题 + 为什么必须是微任务。

1. nextTick 解决什么

Vue 的 DOM 更新是异步批量的:改数据只是把 watcher 推到 scheduler 队列,等到 nextTick(也就是 flushSchedulerQueue)时才真正 patch DOM。所以刚改完数据立刻读 DOM 还是旧值,this.$nextTick(cb) 保证 cb 在本次 DOM 更新之后执行。

2. 为什么用微任务(Promise.then / MutationObserver)

  • 时机刚好:微任务在当前宏任务执行完、浏览器渲染之前清空。这样一轮事件循环内就能完成"改数据 → 渲染函数排队 → patch DOM → 回调执行",回调里能拿到最新 DOM;
  • 不会多等一轮:如果用宏任务(setTimeout),DOM 更新会被推到下一轮事件循环,中间浏览器可能先按旧数据绘制一帧,用户会看到闪一下旧数据;同时多等一轮也会让"改数据后马上测量 DOM"的代码变慢、布局跳变;
  • 不需要等时间:微任务在当前任务末尾自动清空,不用像 setTimeout 那样等最小延迟,时效性最好;
  • 批量更新不被打断:同一轮里多次改数据只 patch 一次,微任务保证回调紧跟在这批更新后面执行。

3. Vue 2 的降级顺序

Promise.then → MutationObserver → setImmediate → MessageChannel → setTimeout,优先选微任务,只有在不支持微任务的环境(老 IE)才退回宏任务。

# 5.10 http 和 websocket 的差异

维度 HTTP WebSocket
通信方向 请求-响应,客户端主动发起(单向拉取) 握手后全双工,服务端可主动推
连接 短连接;HTTP/1.1 keep-alive 可复用,但仍是"一问一答" 一次握手后保持长连接
握手方式 普通 HTTP 报文 用 HTTP Upgrade: websocket + Sec-WebSocket-Key 完成握手,之后不再用 HTTP 数据帧
头部开销 每个请求都带完整头(Cookie、UA 等),几百字节起 握手后是轻量数据帧,头部只有几字节,通信量小
状态 无状态,靠 Cookie/Session/Token 维持身份 有状态,连接本身即会话,可绑定用户
实时性 服务端推送要靠轮询(浪费请求)或 SSE(只能服务端单向推) 真·实时推送,延迟低
适用场景 页面/接口请求、文件传输、幂等 CRUD IM 聊天、行情推送、协同编辑、我们的 ASR 字幕 / 质检 / 小结实时推送
需要注意 缓存、跨域、状态码语义完善 要自己做心跳、断线重连、消息去重与顺序、鉴权(token 放首帧或 URL)、网关/代理对长连接的超时配置

一句话总结:HTTP 适合"我要什么",WebSocket 适合"我要你随时告诉我"。

参考:9. 跨域 (opens new window)、图解HTTP 第9章 (opens new window)。

# 6. 主管面

主管面一般围绕这几类展开(回答思路可复用本文第 3 节):

  1. 之前的业务是什么、做的哪块,需求开发流程怎么走(从需求评审 → 方案 → 开发 → 自测 → 提测 → 上线);
  2. 线上问题 / 运营问题的处理流程(发现 → 定位 → 应急止损 → 复盘 → 改进);
  3. 抗压与加班、稳定性、职业规划;
  4. 面试官会介绍具体业务和团队情况,这时可以顺着问业务方向和技术栈。

综合面试补充:职业规划

答: 1~3年深耕技术,成为团队核心;3~5年向中高级/技术专家发展,能带小团队或独立负责模块。

给面试官的话: 我的规划是短期内扎实做好前端开发,把三维可视化和工程化做深,1~2年内达到中高级水平,能独立负责项目模块。3~5年希望能带小团队或做技术方案设计,往架构方向走。在咱们公司,我了解到有导师带教,我会快速融入,先把手头的事做好,再逐步承担更多责任。

常问问题逐条答案:

1. 技术发展规划,为了达成目标做了什么?

持续学习:看源码、写博客、做开源

项目实践:主动承担复杂模块

复盘总结:每项目结束写总结文档

给面试官的话: 我规划是往中高级前端走,平时会看框架源码、写技术笔记、做 side project。工作中主动接复杂需求,比如性能优化、SDK封装,做完会复盘沉淀。

2. 过往经历中最骄傲的事?

主导/参与某项目从0到1上线

解决重大性能瓶颈,首屏从X秒降到Y秒

封装组件库/SDK,被多项目复用

给面试官的话: 最骄傲的是主导了XX项目的前端架构,从0搭建,封装了公共组件和工具库,上线后支撑了XX业务,首屏性能优化了XX%。

3. 遇到问题怎么处理?有没有引入新东西?

先定位(日志/监控/DevTools)

查文档/搜索/社区

尝试新方案,小范围验证再推广

给面试官的话: 先自己排查,用工具定位根因。如果是技术盲区,查文档和社区,必要时引入新工具或方案,先小范围验证再落地。

4. 工作中感到压力和自豪的事?

压力:紧急上线、线上故障、需求频繁变更

自豪:项目成功上线、性能提升、被认可

给面试官的话: 压力大的是线上紧急问题和密集排期,靠优先级管理和沟通解决。自豪的是自己负责的模块稳定运行,性能优化有明显收益。

5. 遇到困难怎么解决?自己解决还是求助?

先自己查,超过30分钟无进展就求助

求助时带上:问题现象、已尝试方案、怀疑点

事后复盘,沉淀文档

给面试官的话: 先自己排查,卡住超过半小时就带着方案去问,不硬扛。问完会记录解决方案,避免重复踩坑。学到的是:沟通要高效,提问要精准。

6. 上家领导/同事对你的评价?

领导:靠谱、责任心强、技术扎实

同事:好沟通、愿意帮忙、代码规范

给面试官的话: 领导评价我靠谱、有责任心,交给我的事能闭环。同事觉得我好沟通、愿意分享,代码质量稳定。

7. 自我介绍、工作经历、离职原因?

自我介绍:X年前端经验,擅长React/Vue、工程化、性能优化

离职原因:寻求技术成长/业务方向匹配/公司发展

给面试官的话: 我X年前端经验,做过业务开发、组件库、性能优化、SDK。离职是因为想找技术氛围更好、能深入三维可视化方向的团队,和咱们业务方向很匹配。

8. 是否做过管理?如何处理下属摩擦、开发和产品测试意见不一?

带过小团队/带过新人

摩擦:一对一沟通,对齐目标

意见不一:数据说话,拉齐优先级,找共识

给面试官的话: 带过X人小团队/带过新人。遇到开发和产品测试意见不一,我会先听各方诉求,用数据和用户价值判断优先级,实在有分歧就上升给负责人决策,不内耗。

9. 对网上华为黑评怎么看?

理性看待,不跟风

每家公司都有优缺点,看主流

尊重不同声音,但更看重事实

给面试官的话: 网上评价我都理性看,不跟风黑也不盲目吹。任何大公司都有争议,我更关注它实际的技术积累和业务成果。华为在很多领域确实强,这个要客观承认。

10. 如果近期需要和朋友去西安旅游,怎么规划?

定预算和时间

查攻略,定行程(景点、美食、交通)

分工:谁订票、谁订酒店、谁做攻略

留弹性时间

给面试官的话: 我会先和朋友对齐时间和预算,然后分工,我可能负责查路线和美食。用备忘录列好每天的景点和交通,订好酒店门票,留半天机动。西安的话,兵马俑、城墙、回民街这些会安排上。

11. 互联网加班,如何平衡家庭和工作?

提高效率,减少无效加班

重要节点主动投入,平时保证家庭时间

和家人沟通,互相理解

给面试官的话: 我接受互联网的节奏,关键节点会主动投入。平时提高效率,减少无效加班,保证陪伴家人的时间。和家人提前沟通好,互相理解支持。

12. 反问HR:导师带教制度?转内编要求?

导师制:具体怎么带?周期多久?

转正/内编:考核标准是什么?比例多少?

团队:前端团队规模、技术栈、业务方向

给面试官的话: 我想了解下导师带教的具体形式,是全程跟还是阶段性?转内编的考核标准和周期是怎样的?另外想了解下前端团队目前的规模和技术栈方向。

其他注意事项(笔记里已写):

回答不要带口头语("我想一下""嗯""这个")

眼神自然,不盯也不躲

提前进入,不卡点,注意仪容

给面试官的话(综合面收尾): 我的整体规划是先在咱们公司扎实做技术,往三维可视化和中高级前端方向走,能独立扛项目、带小团队。技术上持续学习,业务上快速融入,和团队一起把事做成。